/*
 * ArchPlatform.cpp
 *
 *  Created on: Jan 13, 2010
 *      Author: artur
 */

#include <arm/ArchPlatform.h>
#include <mem/VmMap.h>

extern "C"
{
int raise(int sig)
{
    //    OUTDEBUG("Abort by signal");
    BUG();
}

#ifdef INTERNAL_DIV
unsigned int
__aeabi_uidiv(unsigned int num, unsigned int den)
{
    unsigned int ret = 0;
    unsigned int x;

    if(den == 0)
        raise(8);

    for (x = den; x <= num; x += den, ++ret);
    return ret;
}

unsigned int
__aeabi_uidivmod(unsigned int num, unsigned int den)
{
    unsigned int x;
    for (x = den; x <= num; x += den);
    return (num - x + den);
}

int __aeabi_idivmod(int num, int den)
{
    int sign=0;
    unsigned int x,y;
    if ((num < 0 && den > 0) || (num >= 0 && den < 0)) sign = 1;

    if (num<0) x = (unsigned int)(0-num); else x = (unsigned int)num;
    if (den<0) y = (unsigned int)(0-den); else y = (unsigned int)den;

    if (sign)
        return -__aeabi_uidivmod(x,y);
    else
        return __aeabi_uidivmod(x,y);
}

int
__aeabi_idiv(int num, int den)
{
    int sign=0;
    unsigned int x,y;
    if ((num < 0 && den > 0) || (num >= 0 && den < 0)) sign = 1;

    if (num<0) x = (unsigned int)(0-num); else x = (unsigned int)num;
    if (den<0) y = (unsigned int)(0-den); else y = (unsigned int)den;

    if (sign)
        return -__aeabi_uidiv(x,y);
    else
        return __aeabi_uidiv(x,y);
}
#endif

}

namespace kernel {

ArchPlatform::ArchPlatform() {
	// TODO Auto-generated constructor stub

}

ArchPlatform::~ArchPlatform() {
	// TODO Auto-generated destructor stub
}


void ArchPlatform::_archinit(void)
{
    stack_setup();
#if 0
	/* timer_install(); */
	uchar8_t *spd = (uchar8_t *)(SPD_BASE_R - P_IO_BASE + V_IO_BASE);
	uint32_t *cm_ctrl = (uint32_t *)(CORE_CTRL_R - P_IO_BASE + V_IO_BASE);
	*cm_ctrl = 5;
#endif

	/* copy interrupt vector */
	util::memcpy((void *)IRQ_VECTOR_BASE,
			(const unsigned char *)&exception_vector_start,
			(size_t)&exception_vector_end - (size_t)&exception_vector_start);

	set_p15_c1(get_p15_c1() | CR_V);
}


void *ArchPlatform::_get_data_abort_addr(struct cpu_regs *regs)
{
	return (void *)get_p15_c6();
}

/**
 *  Check MMU flag
 */
bool ArchPlatform::_is_mmu_on(void)
{
	return (get_p15_c1() & 0x1) ? true : false;
}

/**
 * Switch mmu
 */
void ArchPlatform::_switch_memmap (kernel::mem::VmMap &map)
{
    set_p15_c2((uint32_t)map.getPgd());
	flush_tlb();
}

/**
 * Get page directory entry
 */
void *
ArchPlatform::_get_pagedir (void)
{
    return (void *)get_p15_c2();
}


}
